package com.ou.csbs.capstone.models.shapes;

import java.awt.Color;
import java.util.Arrays;
import java.util.Iterator;

import javax.media.opengl.GL2;

import com.ou.csbs.capstone.models.RenderableModel;
import com.ou.csbs.capstone.views.worldwind.WorldWindCanvas;

import gov.nasa.worldwind.geom.Angle;
import gov.nasa.worldwind.geom.LatLon;
import gov.nasa.worldwind.geom.Position;
import gov.nasa.worldwind.geom.Sector;
import gov.nasa.worldwind.geom.Vec4;
import gov.nasa.worldwind.globes.Globe;
import gov.nasa.worldwind.render.DrawContext;
import gov.nasa.worldwind.render.Renderable;
import gov.nasa.worldwind.render.SurfaceText;
import gov.nasa.worldwind.util.SurfaceTileDrawContext;
/**
 * A drawn text object.
 * It is extended off of a SurfaceText so that any picking that occurs during the EditingTool process does not interfere with existing SurfaceText.
 * Secondly, the constructor and certain methods have been added to aid in object creation, in adherence to how the drawing tool is designed to work.
 * Lastly, OpenGL transformation overrides have been added to allow the drawn text to be rotated, as per specification. This includes re-calculating 
 * a bounding Sector to identify when the text is in view or not.
 * 
 * @author Senior Capstone
 */
public class Text extends SurfaceText{

	private double angle;
	private Sector sector;
	private double fontSize;
	
	public Text(String text, Position position, double angle, double size, double fontSize, Color color){
		super(text, position);
		this.setTextSize(size);
		this.angle = angle;
		this.fontSize = fontSize;
		this.color = color;
	}
	public void drawShape(RenderableModel model) {
		model.getDrawingLayer().addRenderable(this);
		WorldWindCanvas.getWorldWindow().redrawNow();
	}
	public void removeShape(RenderableModel model){
		model.getDrawingLayer().removeRenderable(this);
		WorldWindCanvas.getWorldWindow().redrawNow();
	}
	public boolean isDrawn(RenderableModel model) {
		Iterator<Renderable> it =  model.getDrawingLayer().getRenderables().iterator();
		while(it.hasNext()){
			if(it.next().equals(this))
				return true;
		}
		return false;
	}
	public double getAngle(){
		return this.angle;
	}
	public double getFontSize(){
		return this.fontSize;
	}
	public void setFontSize(double size){
		double pixelSize = this.textSizeInMeters/this.fontSize;
		this.fontSize = size;
		this.setTextSize(pixelSize * size);
		this.sector = null;
        this.updateModifiedTime();
		WorldWindCanvas.getWorldWindow().redrawNow();
	}
	@Override
    public void setPosition(Position position){
        this.sector = null;
		this.location = position;
        this.updateModifiedTime();
    }
	
	@Override
	protected void applyDrawTransform( final DrawContext dc, final SurfaceTileDrawContext sdc ){
		//super.applyDrawTransform( dc, sdc );
		Vec4 point = new Vec4(this.location.getLongitude().degrees, this.location.getLatitude().degrees, 1 );
		point = point.transformBy4(sdc.getModelviewMatrix());

		GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility.

		// Translate to location point
		gl.glTranslated(point.x(), point.y(), point.z());
		// Apply the scaling factor to draw the text at the correct geographic size
		gl.glScaled( this.scale / this.location.getLatitude().cos(), this.scale, 1d );
		gl.glRotated( this.angle, 0, 0, -1);
	}

	@Override
	protected Sector computeSector(DrawContext dc)
	{
		if(this.sector == null){
		    updateTextBounds(dc);
			Globe globe = dc.getGlobe();
			double pixelSize = this.textSizeInMeters/this.fontSize;
			double dLatRadians = this.textBounds.getHeight() * pixelSize / globe.getRadius()/ location.getLatitude().cos();
			double dLonRadians = this.textBounds.getWidth() * pixelSize / globe.getRadius() / location.getLatitude().cos();
			Sector sector = new Sector(
					location.getLatitude().subtractRadians(dLatRadians/1.5),
					location.getLatitude().addRadians(dLatRadians/1.5),
					location.getLongitude().addRadians(dLonRadians/1.5),
					location.getLongitude().subtractRadians(dLonRadians/1.5)
					);

			// Rotate sector around location
			this.sector = computeRotatedSectorBounds(sector, this.location, Angle.fromDegrees(angle));
		}
		return this.sector;
	}
	protected Sector computeRotatedSectorBounds(Sector sector, LatLon location, Angle heading)
	{
		if (Math.abs(heading.degrees) < .001)
			return sector;

		LatLon[] corners = new LatLon[] {
				new LatLon(sector.getMaxLatitude(), sector.getMinLongitude()),  // nw
				new LatLon(sector.getMaxLatitude(), sector.getMaxLongitude()),  // ne
				new LatLon(sector.getMinLatitude(), sector.getMinLongitude()),  // sw
				new LatLon(sector.getMinLatitude(), sector.getMaxLongitude()),  // se
		};
		// Rotate corners around location
		for (int i = 0; i < corners.length; i++)
		{
			Angle azimuth = LatLon.greatCircleAzimuth(location, corners[i]);
			Angle distance = LatLon.greatCircleDistance(location, corners[i]);
			corners[i] = LatLon.greatCircleEndPosition(location, azimuth.add(heading), distance);
		}

		return Sector.boundingSector(Arrays.asList(corners));
	}

}
